<?php

/*
 * This file is part of the symfony package.
 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * @package    symfony
 * @subpackage plugin
 * @author     Nicolas Chambrier <naholyr@yahoo.fr>
 * @version    SVN: $Id: $
 */
class BasenahoWikiActions extends sfActions
{

  public function preExecute()
  {
    $this->anonymousEditing = sfConfig::get('app_nahoWikiPlugin_allow_anonymous_edit', false);
    $this->startPage = sfConfig::get('app_nahoWikiPlugin_start_page', 'index');
    $this->credentialsEdit = sfConfig::get('app_nahoWikiPlugin_credentials_edit', array());
    $this->formName = null;

    // Disable escaping
    sfOutputEscaper::markClassesAsSafe(array(
      'nahoWikiContent',
      'nahoWikiPage',
      'nahoWikiRevision',
      'nahoWikiContentPeer',
      'nahoWikiPagePeer',
      'nahoWikiRevisionPeer',
    ));
  }

  protected function setPage(sfWebRequest $request, $page_name = null, $formType = null)
  {
    if ($request->getMethod() == sfRequest::GET || is_null($formType))
    {
      $params = $request->extractParameters(array('page', 'revision_old', 'revision_new', 'revision'));
    }
    else
    {
      $this->formName = sfConfig::get('app_nahoWikiPlugin_'.$formType.'_form_name', 'wiki_'.$formType);
      $params = $request->getParameter($this->formName);
    }

    // Get page from request if not given as parameter (default behaviour)
    if (is_null($page_name))
    {
      $page_name = isset($params['page']) ? $params['page'] : $this->startPage;
    }

    // Handle case insensitivity
    $page_name = strtolower($page_name);

    // Support default page if not specified in namespace
    if (substr($page_name, -1) == ':')
    {
      $page_name .= $this->startPage;
    }

    // Retrieve the page, or start a new one if cannot be found
    $this->page = nahoWikiPagePeer::retrieveByName($page_name);
    if (!$this->page)
    {
      $this->initNewPage($page_name);
    }

    // Retrieve the revision
    // Supports revision_old & revision_new, transformed into revision[old] & revision[new]
    // This trick is required because of sfRouting not recognizing [] in urls
    if (isset($params['revision_old']) && isset($params['revision_new']))
    {
      $params['revision'] = array('old' => $params['revision_old'], 'new' => $params['revision_new']);
      // Cleans request
      if (is_null($this->formName))
      {
        $request->setParameter('revision', $params['revision']);
      }
      else
      {
        $request->addRequestParameters(array($this->formName => array('revision' => $params['revision'])));
      }
    }
    // Can be "revision", "revision[new]", depending on how parameters are passed
    $revision = isset($params['revision']) ? $params['revision'] : $this->page->getLatestRevision();
    if (is_array($revision))
    {
      $revision = $revision['new'];
    }
    $this->revision = $this->page->getRevision($revision);
    if (!$this->revision)
    {
      $this->initNewRevision();
    }

    // Generate the URI parameters to keep trace of the requested page
    $this->uriParams = 'page=' . $this->page->getName();
    if ($this->revision->getRevision() != $this->page->getLatestRevision())
    {
      $this->uriParams .= '&revision=' . $this->revision->getRevision();
    }

    // Permissions management
    $this->canView = $this->page->canView($this->getUser());
    $this->canEdit = $this->page->canEdit($this->getUser());
  }

  protected function initNewRevision(sfWebRequest $request)
  {
    $this->revision = new nahoWikiRevision();
    $this->revision->setnahoWikiPage($this->page);
    $this->revision->initUserName();
    $this->revision->setIdGroupe($request->getParameter('id_groupe'));

    if (!$this->page->isNew())
    {
      $this->revision->setRevision($this->page->getLatestRevision()+1);
    }
  }

  protected function initNewPage($page_name)
  {
    $this->page = new nahoWikiPage;
    $this->page->setName($page_name);
  }

  protected function checkFormName(sfForm $form)
  {
    if ($form->getName() != $this->formName)
    {
      throw new Exception('nahoWikiPlugin configuration error - You changed form name without changing value of corresponding *_form_name option');
    }
  }

  protected function forward403Unless($condition)
  {
    if ($condition)
    {

      return;
    }

    if ($this->getUser()->isAuthenticated())
    {
      return $this->forward(sfConfig::get('sf_secure_module'), sfConfig::get('sf_secure_action'));
    }
    else
    {
      return $this->forward(sfConfig::get('sf_login_module'), sfConfig::get('sf_login_action'));
    }
  }


  protected function updateBreadcrumbs()
  {
    if (!$this->page->isNew())
    {
      $breadcrumbs = $this->getUser()->getAttribute('breadcrumbs', array(), 'nahoWiki');
      if (!in_array($this->page->getName(), $breadcrumbs))
      {
        $breadcrumbs[] = $this->page->getName();
      }
      if (count($breadcrumbs) > sfConfig::get('app_nahoWikiPlugin_max_breadcrumbs', 5))
      {
        array_shift($breadcrumbs);
      }
      $this->getUser()->setAttribute('breadcrumbs', $breadcrumbs, 'nahoWiki');
    }
  }


  public function executeIndex(sfWebRequest $request)
  {

    return $this->forward('nahoWiki', 'view');
  }

  public function executeView(sfWebRequest $request)
  {
    $this->setPage($request);
    $this->forward403Unless($this->canView);

    $this->updateBreadcrumbs();

    return sfView::SUCCESS;
  }

  public function executeEdit(sfWebRequest $request)
  {
    $this->setPage($request, null, 'edit');
    $this->form = new nahoWikiEditForm($this->revision, array(), array('can-edit' => $this->canEdit));

    // Do not reject here if not canEdit, cause it then fallbacks on "view source" feature
    $this->forward403Unless($this->canView);

    // Generate the username (this is done by the Revision model)
    $tmp_revision = new nahoWikiRevision();
    $tmp_revision->initUserName();
    $tmp_revision->setIdGroupe($request->getParameter('id_groupe'));
    $this->userName = $tmp_revision->getUserName();

    // Save changes
    $this->showPreview = false;
    if ($request->isMethod(sfRequest::POST))
    {
      // To prevent nahoWiki administrators to change form name without touching app.yml, force the behavior !
      $this->checkFormName($this->form);

      // Here we must be able to edit
      $this->forward403Unless($this->canEdit);
      $this->form->bind($request->getParameter($this->form->getName()));

      if ($this->form->isValid())
      {
        $this->showPreview = $this->form->getValue('request-preview');
        if ($this->form->save())
        {
          $this->redirect('nahoWiki/view?page=' . $this->page->getName());
        }
      }
    }

    return sfView::SUCCESS;
  }

  public function executeHistory(sfWebRequest $request)
  {
    $this->setPage($request, null, 'diff');
    $this->forward403Unless($this->canView);

    $this->form = new nahoWikiHistoryForm($this->page);

    return sfView::SUCCESS;
  }

  public function executeDiff(sfWebRequest $request)
  {
    $this->setPage($request, null, 'diff'); // $this->revision is revision2
    $this->forward403Unless($this->canView);

    $this->forward404If($this->page->isNew());
    $this->forward404If($this->revision->isNew());

    $this->form = new nahoWikiHistoryForm($this->page);

    if ($request->getMethod() == sfRequest::POST)
    {
      $this->form->bind($request->getParameter($this->form->getName()));
      // To prevent nahoWiki administrators to change form name without touching app.yml, force the behavior !
      // Note : this has not to be done with GET method, as it must work with routing
      $this->checkFormName($this->form); // Okay, it should ne be necessary as we should come from history, but still...
    }
    else
    {
      $this->form->bind($request->extractParameters($this->form->getWidgetSchema()->getPositions()));
    }

    $this->forward404Unless($this->form->isValid());

    $this->revision1 = $this->form->getRevision('old');
    $this->forward404Unless($this->revision1);

    $this->revision2 = $this->form->getRevision('new');
    $this->forward404Unless($this->revision2);

    $this->diff = $this->form->renderDiff($this->form->getValue('mode'));

    // Direct download
    if ($request->getParameter('raw'))
    {
      $this->getResponse()->setContentType('text/plain');
      $this->renderText($this->diff);

      return sfView::NONE;
    }

    return sfView::SUCCESS;
  }

  public function executeUser(sfWebRequest $request)
  {
    $this->setPage($request, 'User:' . $request->getParameter('name'));
    $this->forward403Unless($this->canView);

    return sfView::SUCCESS;
  }

  protected function buildIndexTree(&$tree, $path, $fullpath, $expanded)
  {
    if (count($path) == 1)
    {
      $tree[$path[0]] = $fullpath;
    }
    else
    {
      $category = array_shift($path) . ':';
      if (!isset($tree[$category]))
      {
        $tree[$category] = array();
      }
      if (count($expanded) && $category == $expanded[0] . ':')
      {
        array_shift($expanded);
        $this->buildIndexTree($tree[$category], $path, $fullpath, $expanded);
      }
    }
  }

  public function executeBrowse(sfWebRequest $request)
  {
    $this->setPage($request);

    $path = $request->getParameter('path');
    $tree = array();

    $c = new Criteria;
    $c->addAscendingOrderByColumn(nahoWikiPagePeer::NAME);
    $pages = nahoWikiPagePeer::doSelect($c);

    foreach ($pages as $page)
    {
      $this->buildIndexTree($tree, explode(':', $page->getName()), $page->getName(), explode(':', $path));
    }

    $this->tree = $tree;
    $this->uriParams = 'page=' . urlencode($request->getParameter('page'));

    return sfView::SUCCESS;
  }

}
